(function() {"use strict";
    const PINYIN_DICT = window.PINYIN_DICT;
    
    const get_raw_type = v => Object.prototype.toString.call(v);
    const TYPE_ARRAY = get_raw_type([]);
    const TYPE_OBJECT = get_raw_type({});
    const TYPE_STRING = get_raw_type('');
    
    const is_array = v => get_raw_type(v) === TYPE_ARRAY;
    const is_object = v => get_raw_type(v) === TYPE_OBJECT;
    const is_string = v => get_raw_type(v) === TYPE_STRING;
    const is_mixed_struct = v => is_array(v) || is_object(v);
    
    var w = window||global;
    w.JKSearcher = new class {
        /**
         * 创建搜索索引
         * 可以通过索引直接匹配关键字
         * @param str
         * @param withoutRaw
         * @returns {[]}
         */
        createIndexes(str, withoutRaw) {
            str = String(str);
            let indexes = [];
            let $this = this;
            Object.defineProperty(indexes, '__isJKSearcherPYIndexes', {value:true});
            
            if(!withoutRaw) {
                Object.defineProperty(indexes, 'raw', {value:str});
            }
            
            Object.defineProperty(indexes, 'search', {
                value:function(word, option) {
                    return $this.search(indexes, word, option);
                }
            });
            
            Object.defineProperty(indexes, 'match', {
                value:function(word, option) {
                    if(withoutRaw) {
                        console.warn('当前使用的是纯索引模式(当前指定了 createIndexes() 的第二个参数为true), 不支持 match 方法');
                        return false;
                    }
                    
                    return $this.match(indexes, word, option);
                }
            });
            
            Object.defineProperty(indexes, 'highlight', {
                value:function(word, option) {
                    if(withoutRaw) {
                        console.warn('当前使用的是纯索引模式(当前指定了 createIndexes() 的第二个参数为true), 不支持 highlight 方法');
                        return false;
                    }
                    
                    return $this.highlight(indexes, word, option);
                }
            });
            
            for(let i=0; i<str.length; i++) {
                let curr = str[i];
                
                if(PINYIN_DICT[curr]) {
                    let pyTmp = {};
                    let pinyins = PINYIN_DICT[curr];
                    for(let j=0; j<pinyins.length; j++) {
                        pyTmp[pinyins[j][0]] = 1;
                    }
                    
                    pyTmp[curr] = 1;
                    
                    indexes.push({
                        index: i,
                        value: pinyins.concat(Object.keys(pyTmp))
                            .sort((a,b)=>b.length-a.length),
                        py:true
                    });
                } else {
                    if(indexes.length && !indexes[indexes.length-1].py) {
                        indexes[indexes.length-1].value += curr;
                    } else {
                        indexes.push({index:i, value:curr});
                    }
                }
            }
            
            return indexes;
        }
        
        /**
         * @param str 待搜索字符串
         * @param word 搜索关键字
         * @param option 搜索选项
         *   sensitive 布尔值,为true表示区分大小写, false表示不区分, 默认false
         *   all 布尔值,为true表示返回所有的匹配项, 为false则只返回第一个匹配的项目, 默认false, 若设置multipleWords为true, 则此项不可用
         *   multipleWords 布尔值,为true支持匹配多个关键字(按顺序, 连续查找)
         * @returns {Boolean|Array} 找到匹配返回匹配的字符起始和结束坐标, 没找到返回false
         */
        search(str, word, option) {
            option = option || {};
            let all = option.all;
            let sensitive = option.sensitive;
            let multipleWords = option.multipleWords;
            
            let indexes = str.__isJKSearcherPYIndexes ? str : this.createIndexes(str, true);
            
            if(indexes.length == 0) {
                return false;
            }
            
            let words = word;
            words = is_array(words) ? words : [word];
            let wordLows = words.map(r=>r.toLowerCase());
            
            if(!sensitive) {
                words = wordLows;
            }
            
            if(multipleWords) {
                all = false;
            } else {
                //没有开启多关键字搜索只能搜第一个关键字
                words = [words[0]];
            }
            
            function make_as_search_ret(ret) {
                Object.defineProperty(ret, '__isJKSearcherSearchResult', {get() {return true;}});
                Object.defineProperty(ret, '__isJKSearcherSearchMultipleWords', {get() {return multipleWords;}});
                return ret;
            }
            
            //检查单个匹配项目
            let check_match = function(word, wordLowCase, indexes, idxStart, idxChildStart) {
                let wordIndex = 0;
                
                for(let i=idxStart; i<indexes.length; i++) {
                    let index = indexes[i];
                    let value = index.value;
                    
                    if(index.py) {
                        let pyfound = false;
                        
                        for(let j=idxChildStart; j<value.length; j++) {
                            let len = Math.min(value[j].length, wordLowCase.length - wordIndex);
                            if(wordLowCase.substr(wordIndex, len) == value[j].substr(0, len)) {
                                wordIndex += len;
                                pyfound = true;
                                
                                if(wordIndex >= wordLowCase.length) {
                                    return [i, j];
                                }
                                
                                break;
                            }
                        }
                        
                        if(!pyfound) {
                            return false;
                        }
                    } else {
                        if(!sensitive) {
                            value = value.toLowerCase();
                        }
                        
                        for(let j=idxChildStart; j<value.length; j++) {
                            if(value[j] != word[wordIndex]) {
                                return false;
                            } else {
                                wordIndex ++;
                                
                                if(wordIndex >= word.length) {
                                    return [i, j];
                                }
                            }
                        }
                        
                        //当前索引字段已经匹配完了
                        idxChildStart = 0;
                    }
                }
                
                return false;
            }
            
            let indexesIndex = 0;
            let indexesChildIndex = 0;
            let allMatchs = [];
            let currentWordIndex = 0
            
            while(true) {
                let currentWord = words[currentWordIndex];
                let currentWordLowCase = wordLows[currentWordIndex];
                let indexItem = indexes[indexesIndex];
                let findResult = check_match(currentWord, currentWordLowCase, indexes, indexesIndex, indexesChildIndex);
                
                if(findResult) {
                    let findIndexesIndex = findResult[0];
                    let findIndexesChildIndex = findResult[1];
                    let findIndexesItem = indexes[findIndexesIndex];
                    
                    let strIndexInfo = [
                        indexItem.index + (indexItem.py ?  0 : indexesChildIndex),
                        findIndexesItem.index + (findIndexesItem.py ?  0 : findIndexesChildIndex)
                    ];
                    
                    //只有一个关键词
                    if(!all && words.length == 1) {
                        return make_as_search_ret([strIndexInfo]);
                    }
                    
                    allMatchs.push(strIndexInfo);
                    
                    if(!findIndexesItem.py && findIndexesChildIndex < findIndexesItem.value.length - 1) {
                        indexesIndex = findIndexesIndex;
                        indexesChildIndex ++;
                    } else {
                        indexesIndex = findIndexesIndex + 1;
                        indexesChildIndex = 0;
                    }
                    
                    if(multipleWords) {
                        currentWordIndex ++;
                        
                        //所有关键词均已匹配到
                        if(currentWordIndex >= words.length) {
                            return allMatchs.length ? make_as_search_ret(allMatchs) : false;
                        }
                    }
                } else {
                    if(!indexItem.py && indexesChildIndex < indexItem.value.length - 1) {
                        indexesChildIndex ++;
                    } else {
                        indexesIndex ++;
                        indexesChildIndex = 0;
                    }
                }
                
                if(indexesIndex > indexes.length-1) {
                    break ;
                }
            }
    
            if(multipleWords && allMatchs.length != words.length) {
                return false;
            } 
            
            return allMatchs.length ? make_as_search_ret(allMatchs) : false;
        }
        
        /**
         * 返回匹配的字符子串, 若无匹配则返回空数组
         * @param str
         * @param word
         * @param option
         * @returns {Boolean|Array}
         */
        match(str, word, option) {
            option = option || {};
            let matchs = this.search(str, word, option);
            
            if(!matchs) {
                return false;
            }
            
            let segment = [];
            let raw = str.__isJKSearcherPYIndexes ? str.raw : str;
            
            for(let i in matchs) {
                let match = matchs[i];
                let x = match[0];
                let y = match[1];
                
                segment.push(raw.substr(x, y-x+1));
            }
            
            return [ ... new Set(segment)];
        }
        
        /**
         * 高亮匹配项
         * @param {string|object} str - 待匹配字符串或索引
         * @param word 关键字字符串或search返回的匹配结果
         * @param option 高亮选项
         *  callback: 一个函数, 用于替换匹配项格式 string => string
         *  其他选项参考search函数
         * @returns {string|*}
         */
        highlight(str, word, option) {
            option = option || {};
            let callback = option.callback || (row => '<b>'+row+'</b>');
            delete option.callback;
            
            let matchs = word.__isJKSearcherSearchResult ? word : this.search(str, word, option);
            let raw = str.__isJKSearcherPYIndexes ? str.raw : str;
            
            if(!matchs) {
                return raw;
            }
            
            let segment = [];
            let prev = 0;
            
            for(let i in matchs) {
                let match = matchs[i];
                let x = match[0];
                let y = match[1];
                
                segment.push(raw.substr(prev, x-prev));
                segment.push({hi:true, value:raw.substr(x, y-x+1), x, y, length: y-x+1});
                prev = y + 1;
            }
            
            if(prev <= raw.length - 1) {
                segment.push(raw.substr(prev));
            }
            
            let histr = '';
            
            for(let item of segment) {
                if(item.hi) {
                    histr += callback(item.value, item);
                } else {
                    histr += item;
                }
            }
            
            return histr;
        }
    };
    
    function ds_take_datarow_unique_value(data, index, uniqueKey) {
        return uniqueKey ? String(data[index][uniqueKey]) : index;
    }
    
    function ds_take_datarow_value(data, index, valueKey) {
        if(valueKey === true) {
            return index;
        } else {
            return valueKey ? data[index][valueKey] : data[index];
        } 
    }
    
    function ds_take_datarow_label_value(data, index, labelKey) {
        let row = data[index];
        let label = is_mixed_struct(row) ? row[labelKey] : String(row);

        if(label === undefined) {
            console.groupCollapsed(`%c据集合获取label值为 %cundefined%c, %clabelKey=%c${labelKey}%c index=%c${index}`,
                "color:red", "color:blue", "color:red", "color:red", "color:black", "color:red", "color:black");
            console.trace();
            console.groupEnd();
            label = '';
        }
        
        return label;
    }
    
    /**
     * 移除包含指定所以的历史记录
     * @param history
     * @param index
     * @returns {*}
     */
    function ds_remove_history_with_index(history, index) {
        if(!history) {
            return {};
        }
        
        if(history[0]) {
            for(let i in history[0]) {
                let row = history[0][i];
                row.values = row.values.filter(v => v != index);
                
                if (row.values.length == 0) {
                    delete history[0][i];
                }
            }
        }
    
        if(history[1]) {
            for(let i in history[1]) {
                let row = history[1][i];
                row.values = row.values.filter(v => v != index);
            
                if (row.values.length == 0) {
                    delete history[1][i];
                }
            }
        }
        
        return history;
    }
    
    function ds_unstable_history(history) {
        if(!history) {
            return {};
        }
        
        if(history[0]) {
            for(let i in history[0]) {
                history[0][i].stable = false;
            }
        }
    
        if(history[1]) {
            for(let i in history[1]) {
                history[1][i].stable = false;
            }
        }
        
        return history;
    }
    
    /**
     * 移除在指定索引以外的历史记录
     * @param history
     * @param index
     * @returns {*}
     */
    function ds_remove_history_except(history, index) {
        if(!history) {
            return {};
        }
        
        if(history[0]) {
            for(let i in history[0]) {
                let row = history[0][i];
                row.values = row.values.filter(v => index.indexOf(v) != -1)
        
                if(row.values.length == 0) {
                    delete history[0][i];
                }
            }
        }
    
        if(history[0]) {
            for(let i in history[1]) {
                let row = history[1][i];
                row.values = row.values.filter(v => index.indexOf(v) != -1)
            
                if(row.values.length == 0) {
                    delete history[1][i];
                }
            }
        }
        
        
        return history;
    }
    
    function take_columns(data, column) {
        let ret = [];
        for(let i in data) {
            let row = data[i];
            ret.push(row[column]);
        }
        
        return ret;
    }
    
    class JKDataSet {
        constructor(data, option) {
            option = option || {};
            option.uniqueKey = (option.uniqueKey || option.uniqueKey === 0) ?  String(option.uniqueKey) : null;
            this.option = option;
            
            this._indexes = {};
            this._history = {};
            this._state = {
                indexed: {},
                indexAll: {}
            };
            this.updateData(data, true);
        }
    
        /**
         * 重新生成索引
         * @param labelKeys
         * @returns {JKDataSet}
         */
        reIndex(labelKeys) {
            labelKeys = labelKeys ? labelKeys : Object.keys(this._indexes);
            labelKeys = is_array(labelKeys) ? labelKeys : [labelKeys];
            let uniqueKey = this.option.uniqueKey;
            let data = this.data;
    
            for(let i in labelKeys) {
                let labelKey = labelKeys[i];
                let reIndexAll = this._state.indexAll[labelKey] || !this._indexes[labelKey];
                this._state.indexAll[labelKey] = false;
                this._state.indexed[labelKey] = true;
                this._history[labelKey]  = ds_unstable_history(this._history[labelKey]);
                
                let reIndexedCount = 0;
                let reIndexedKeys = {};
    
                if(reIndexAll) {
                    this._indexes[labelKey] = {};
                }
    
                for(let index in data) {
                    let label = ds_take_datarow_label_value(data, index, labelKey);
                    label = String(label);
                    let uniqueValue = ds_take_datarow_unique_value(data, index, uniqueKey);
                    let currentIndex = null;
                    
                    if(!reIndexAll) {
                        currentIndex = this._indexes[labelKey] ? this._indexes[labelKey][uniqueValue] : null;
                    }
                    
                    if(reIndexAll || !currentIndex || currentIndex.label.length != label.length || currentIndex.label != label) {
                        this._indexes[labelKey][uniqueValue] = {
                            indexes: JKSearcher.createIndexes(label, true),
                            label, index
                        }
    
                        this._history[labelKey] = ds_remove_history_with_index(this._history[labelKey], index);
                    }
    
                    if(!reIndexAll) {
                        reIndexedCount ++;
                        reIndexedKeys[uniqueValue] = true;
                    }
                }
    
                this._history[labelKey] = ds_remove_history_except(this._history[labelKey], Object.keys(data));
    
                if(!reIndexAll) {
                    for(let uniqueValue in this._indexes[labelKey]) {
                        if(!reIndexedKeys[uniqueValue]) {
                            delete this._indexes[labelKey][uniqueValue];
                        }
                    }
                }
            }
            
            return this;
        }
    
        /**
         * 搜索数据集
         * @param word
         * @param option
         *   highlight: 一个布尔值, 为true表示高亮匹配项
         *   highlightCallback: 匹配项回调函数
         *   highlightSaveKey: 高亮后的文本储存的key, 默认为 _label
         *   nosort: 是否取消排序(当从搜索历史中搜素出结果可能顺序跟原来的不一致, 需额外排序)
         *   timecost: 是否在控制台打印搜索耗时
         *   其他参数参考 JKSearcher.search 函数
         * @returns {{}|*[]}
         */
        search(word, option) {
            option = option || {};
            let highlight = option.highlight;
            let highlightCallback = option.highlightCallback || (v => `<b>${v}</b>`);
            let highlightSaveKey = option.highlightSaveKey || '_label';
            let labelKey = option.labelKey || 'label';
            let valueKey = (option.valueKey || option.valueKey === 0) ?  option.valueKey : null;
            valueKey = valueKey !== null ? String(valueKey) : valueKey;
            let sensitive = option.sensitive || 0;
            sensitive = sensitive?1:0;
            let nosort = option.nosort; 
            let timeBegin = option.timecost ? (new Date).getTime() : 0;
            let time_cost_report = _ => option.timecost && console.log("耗时 %c"+((new Date).getTime()-timeBegin) + ' %c毫秒', "color:purple;", "color:;")
            
            word = is_array(word) ? word : [word];
            word = word.filter(a=>a||a===0);
            let needHighlight = highlight && (!valueKey || valueKey === highlightSaveKey);
            option.all = needHighlight ? option.all : false;
            let isOne = Object.prototype.toString.call(labelKey) != Object.prototype.toString.call([]);
            let labelKeys = isOne ? [labelKey] : labelKey;
            let get_hi_save_key = v => isOne ? highlightSaveKey : (highlightSaveKey[v] || '_' + v);
            
            if(word.length == 0) {
                if(!highlight) {
                    return this.data;
                }
                
                for(let i in this.data) {
                    let row = this.data[i];
                    
                    if(is_mixed_struct(row)) {
                        for(let lIndex in labelKeys) {
                            let labelKey = labelKeys[lIndex];
                            let saveKey = get_hi_save_key(labelKey);
                            row[saveKey] = ds_take_datarow_label_value(this.data, i, labelKey);
                        }
                    }
                }
                
                return this.data;
            }
            
            let wordKey = option.multipleWords ? 'm|'+word.join(' ') : 's|'+word[0];
            //已经匹配的数据
            let matchedData = [];
            //已经匹配过的数据下标
            let matchedIndex = {};
            //某个label匹配到的数据下标
            let labelMatchedIndex = {};
            //存放已找到的不确定数据下标
            let notclearDataKeys={};
            //记录多个label是否完整匹配
            let matchEnd = {};
            
            //从搜索历史中拿数据
            for(let lIndex in labelKeys) {
                let labelKey = labelKeys[lIndex];
    
                //还没有索引, 创建索引
                if(!this._state.indexed[labelKey]) {
                    this.reIndex([labelKey]);
                }
    
                labelMatchedIndex[labelKey] = labelMatchedIndex[labelKey] || {};
                notclearDataKeys[labelKey] = notclearDataKeys[labelKey] || {};
                
                if(this._history[labelKey] && this._history[labelKey][sensitive]) {
                    let _historys = this._history[labelKey][sensitive];
                    let lastClearlyHWord = null;
                    let lastClearlyHWordItemLen = 0;
                    let lastNotClearHWord = null;
        
                    for(let hword in _historys) {
                        let chwPos = hword.indexOf(wordKey);
                        let nchwPos = wordKey.indexOf(hword);
                        
                        //历史关键词对当前关键词没有任何帮助
                        //直接跳过
                        if(chwPos == -1 && nchwPos == -1) {
                            continue;
                        }
    
                        let items = _historys[hword];
                        
                        if(chwPos != -1 && (lastClearlyHWord === null || lastClearlyHWordItemLen < items.length)) {
                            lastClearlyHWord = hword;
                            lastClearlyHWordItemLen = items.length;
                        }
    
                        if(nchwPos != -1 && (lastNotClearHWord === null || lastNotClearHWord.length < hword.length)) {
                            lastNotClearHWord = hword;
                        }
                    }
        
                    //已确定的
                    if(lastClearlyHWord) {
                        let matchedHistoryInfo = _historys[lastClearlyHWord] ? _historys[lastClearlyHWord] : null;
            
                        if(matchedHistoryInfo) {
                            for(let i in matchedHistoryInfo.values) {
                                let index = matchedHistoryInfo.values[i];
                                
                                if(matchedIndex[index]) {
                                    continue;
                                }
                                
                                matchedData.push({value:ds_take_datarow_value(this.data, index, valueKey), index, labelKey});
                                matchedIndex[index] = true;
                                labelMatchedIndex[labelKey][index] = true;
                            }
                
                            if(lastClearlyHWord == wordKey && matchedHistoryInfo.stable) {
                                matchEnd[labelKey] = true;
                            }
                        }
                    }
                    
                    //未确定的
                    if(lastNotClearHWord) {
                        let hinfo = _historys[lastNotClearHWord] ? _historys[lastNotClearHWord] : null;
                        if(hinfo) {
                            notclearDataKeys[labelKey] = hinfo.values;
                        }
                    }
                }
            }
            
            
            let searchOption = Object.assign({}, option);
            let matchEndValue = Object.values(matchEnd);
            let fullMatchFromHistory = matchEndValue.length > 0 && matchEndValue.length == matchEndValue.reduce((a,b) => a+b, 0)
            
            //历史(缓存)中没有完全查找到
            //从实际数据中搜索
            if(!fullMatchFromHistory) {
                let _match_append = (data, i, labelKey) => {
                    let uniqueValue = ds_take_datarow_unique_value(data, i, this.option.uniqueKey);
                    let searchLabelKeys = [labelKey];
                    
                    if(typeof labelKey != undefined) {
                        searchLabelKeys = labelKeys;
                    }
                    
                    for(let lIndex in searchLabelKeys) {
                        let labelKey = labelKeys[lIndex];
        
                        if(matchEnd[labelKey]) {
                            continue;
                        }
        
                        let dataIndexInfo = this._indexes[labelKey][uniqueValue];
                        if(!dataIndexInfo) {
                            continue;
                        }
        
                        labelMatchedIndex[labelKey] = labelMatchedIndex[labelKey] || {};
        
                        let searchRet = dataIndexInfo.indexes.search(word, searchOption);
                        if(searchRet) {
                            matchedIndex[i] = true;
                            labelMatchedIndex[labelKey][i] = true;
                            matchedData.push({value:ds_take_datarow_value(data, i, valueKey), index:i, searchRet, labelKey});
                            return true;
                        }
                    }
                    
                    return false;
                };
                
                //已经明确的范围, 单并未确定那些是匹配的
                //只需要从这里去查找即可, 以缩小范围
                if(notclearDataKeys.length) {
                    for(let li in labelKeys) {
                        let labelKey = labelKeys[li];
                        notclearDataKeys[labelKey] = notclearDataKeys[labelKey]|| [];
                        
                        for(let k in notclearDataKeys[labelKey]) {
                            let i = notclearDataKeys[labelKey][k];
        
                            if(matchedIndex[i]) {
                                continue;
                            }
        
                            _match_append(this.data, i, labelKey);
                        }
                    }
                } else {
                    for(let i in this.data) {
                        if(matchedIndex[i]) {
                            continue;
                        }
        
                        _match_append(this.data, i);
                    }
                }
    
                //重新更新搜索历史
                for(let lIndex in labelKeys) {
                    let labelKey = labelKeys[lIndex];
                    if(!this._history[labelKey]) {
                        this._history[labelKey] = {};
                    }
                    if(!this._history[labelKey][sensitive]) {
                        this._history[labelKey][sensitive] = {};
                    }
                    this._history[labelKey][sensitive][wordKey] = {
                        stable: true,
                        values: Object.keys(labelMatchedIndex[labelKey]),
                    };
                }
            }
    
            //手动指定不需要排序
            if(!nosort) {
                function sort_matched(matched, keys) {
                    let keyMap = {};
                    for(let i in keys) {
                        let key = keys[i];
                        keyMap[key] = i;
                    }
        
                    return matched.sort((l,r) => {
                        return keyMap[l.index] - keyMap[r.index];
                    });
                }
    
                matchedData = sort_matched(matchedData, Object.keys(this.data)); 
            }
            
            if(needHighlight) {
                for(let i in matchedData) {
                    let row = matchedData[i];
                    let hitext;
                    let label = ds_take_datarow_label_value(this.data, row.index, row.labelKey);
                    
                    if(row.searchRet) {
                        hitext = JKSearcher.highlight(String(label), row.searchRet, Object.assign({}, searchOption, {callback: highlightCallback}));
                    } else {
                        let uniqueValue = ds_take_datarow_unique_value(this.data, row.index, this.option.uniqueKey);
                        let rowIndexInfo = this._indexes[row.labelKey][uniqueValue];
                        let indexes = rowIndexInfo.indexes;
                        indexes.raw = String(label);
                        hitext = JKSearcher.highlight(indexes, word, Object.assign({}, searchOption, {callback: highlightCallback}));
                        delete indexes.raw;
                    }
                    
                    if(!is_mixed_struct(row.value)) {
                        row.value = hitext;
                    } else {
                        for(let lIndex in labelKeys) {
                            let labelKey = labelKeys[lIndex];
                            
                            //没有匹配上的还原成原来的值
                            if(labelKey != row.labelKey) {
                                let saveKey = get_hi_save_key(labelKey);
                                row.value[saveKey] = String(ds_take_datarow_label_value(this.data, row.index, labelKey));
                            }
                        }
    
                        let saveKey = get_hi_save_key(row.labelKey);
                        row.value[saveKey] = hitext;
                    }
                }
            }
    
            if(is_object(this.data)) {
                let objData = {};
                for(let i in matchedData) {
                    objData[matchedData[i].index] = matchedData[i].value;
                }
                time_cost_report();
                return objData;
            } else {
                time_cost_report();
                return take_columns(matchedData, 'value');
            }
        }
    
        /**
         * 更新数据集数据
         * @param data
         * @param reIndexAll 是否更新所有索引
         * @returns {JKDataSet}
         */
        updateData(data, reIndexAll) {
            this.data = data;
            this._state.indexed = {};
            
            if(reIndexAll) {
                for(let key in this._indexes) {
                    this._state.indexAll[key] = true;
                }
            }
            
            return this;
        }
        
        getRawData() {
            return this.data;
        }
    }
    
    w.JKSearcher.createDataSet = function(data, option) {
        return new JKDataSet(data, option);
    }
    
    return w.JKSearcher;
})();
